package com.android.accessibility.function;

import java.util.ArrayList;
import java.util.List;

import android.accessibilityservice.AccessibilityService;
import android.annotation.SuppressLint;
import android.text.TextUtils;
import android.view.accessibility.AccessibilityNodeInfo;

import com.android.accessibility.utils.Log;

public class Helper {

    public static AccessibilityNodeInfo sFindAccessibilityNodeInfo;

    @SuppressLint({ "InlinedApi", "NewApi" })
    public static boolean findAndPerformAction(AccessibilityService service, String text) {
        AccessibilityNodeInfo nodeInfo = service.getRootInActiveWindow();
        if (nodeInfo == null) {
            return false;
        }
        List<AccessibilityNodeInfo> nodes = nodeInfo
                .findAccessibilityNodeInfosByText(text);
        if (nodes != null && nodes.size() > 0) {
            return findClickViewAndPerformClick(nodes.get(0));
        }
        return false;
    }

    private static AccessibilityNodeInfo findClickableNodeInfo(final AccessibilityNodeInfo node) {
        AccessibilityNodeInfo tmpNode = node;
        while (tmpNode != null
                && !(tmpNode.isEnabled() && tmpNode.isClickable())) {
            tmpNode = tmpNode.getParent();
        }
        if (tmpNode != null && tmpNode.isEnabled() && tmpNode.isClickable()) {
            return tmpNode;
        }
        return null;
    }

    @SuppressLint("InlinedApi")
    public static boolean findClickViewAndPerformClick(final AccessibilityNodeInfo node) {
        AccessibilityNodeInfo tmpNode = findClickableNodeInfo(node);
        if (tmpNode != null) {
            tmpNode.performAction(AccessibilityNodeInfo.ACTION_CLICK);
            return true;
        }
        return false;
    }

    /*
    @SuppressLint({ "InlinedApi", "NewApi" })
    public static void findAndPerformActionByViewId(AccessibilityService service, String viewId) {
        AccessibilityNodeInfo nodeInfo = service.getRootInActiveWindow();
        if (nodeInfo == null) {
            return;
        }
        try {
            List<AccessibilityNodeInfo> nodes = nodeInfo
                    .findAccessibilityNodeInfosByViewId(viewId);
            if (nodes != null && nodes.size() > 0) {
                findClickViewAndPerformClick(nodes.get(0));
            }
        } catch (NoSuchMethodError e) {
            Log.d(Log.TAG, "error : " + e);
        }
    }
    */

    public static AccessibilityNodeInfo findViewNodeInfo(
            AccessibilityNodeInfo nodeInfo, String className) {
        return findViewNodeInfo(nodeInfo, className, 0);
    }

    public static AccessibilityNodeInfo findViewNodeInfo(
            AccessibilityNodeInfo nodeInfo, String className, int order) {
        List<AccessibilityNodeInfo> list = new ArrayList<AccessibilityNodeInfo>();
        findViewNodeInfoLocked(nodeInfo, className, list);
        if (list.size() > order) {
            return list.get(order);
        }
        return null;
    }

    @SuppressLint("NewApi")
    private static void findViewNodeInfoLocked(
            AccessibilityNodeInfo nodeInfo, String className,
            List<AccessibilityNodeInfo> list) {
        if (TextUtils.isEmpty(className) || list == null) {
            return;
        }
        if (nodeInfo != null) {
            for (int index = 0; index < nodeInfo.getChildCount(); index++) {
                AccessibilityNodeInfo info = nodeInfo.getChild(index);
                if (info != null && className.equals(info.getClassName())) {
                    list.add(info);
                } else {
                    findViewNodeInfoLocked(info, className, list);
                }
            }
        }
    }

    public static List<AccessibilityNodeInfo> findClickableNodeListByText(AccessibilityService service,
            String text) {
        if (service == null || service.getRootInActiveWindow() == null) {
            return null;
        }
        List<AccessibilityNodeInfo> nodes = service.getRootInActiveWindow()
                .findAccessibilityNodeInfosByText(text);
        AccessibilityNodeInfo clickNodeInfo = null;
        List<AccessibilityNodeInfo> clickNodeList = new ArrayList<AccessibilityNodeInfo>();
        if (nodes != null && nodes.size() > 0) {
            for (AccessibilityNodeInfo nodeInfo : nodes) {
                clickNodeInfo = findClickableNodeInfo(nodeInfo);
                if (clickNodeInfo != null) {
                    clickNodeList.add(clickNodeInfo);
                }
            }
        }
        return clickNodeList;
    }

    public static void printAllNodeInfo(AccessibilityService service) {
        if (service == null) {
            return ;
        }
        AccessibilityNodeInfo rootNodeInfo = service.getRootInActiveWindow();
        printNodeInfo(rootNodeInfo);
    }

    public static void printNodeInfo(AccessibilityNodeInfo rootNodeInfo) {
        int count = rootNodeInfo.getChildCount();
        if (count > 0) {
            for (int index = 0; index < count; index++) {
                AccessibilityNodeInfo info = rootNodeInfo.getChild(index);
                if (info != null) {
                    Log.d(Log.TAG, "" + info);
                    printNodeInfo(info);
                }
            }
        }
    }

    public static List<AccessibilityNodeInfo> findClickableNodeInfoList(
            AccessibilityNodeInfo rootNodeInfo) {
        List<AccessibilityNodeInfo> list = new ArrayList<AccessibilityNodeInfo>();
        findClickableNodeInfoLocked(rootNodeInfo, list);
        return list;
    }

    @SuppressLint("NewApi")
    private static void findClickableNodeInfoLocked(
            AccessibilityNodeInfo nodeInfo, List<AccessibilityNodeInfo> list) {
        if (list == null) {
            return;
        }
        if (nodeInfo != null) {
            for (int index = 0; index < nodeInfo.getChildCount(); index++) {
                AccessibilityNodeInfo info = nodeInfo.getChild(index);
                if (info != null && info.isClickable()) {
                    list.add(info);
                } else {
                    findClickableNodeInfoLocked(info, list);
                }
            }
        }
    }
}
